СРЕДА.отд
Главная     ◄Глагол     ◄Азбука     ◄Задачи на Глаголе     Примеры приложений ►   Среда разработки ►   Отладка программ ►   Отличия от Оберона ►   Отличия от Паскаля ►   Ассемблер ARM ►   Глагол для ARM ►   ? и Ответы
 
 glagol.png Программируем по-русски
 

Основная задача Глагола — дать человеку возможность воплощать свои мысли на языке, близком к его родному языку.

Издатель Глагола
 

 
(*~\Глагол\Отделы\Среда~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**)                         ОТДЕЛ СРЕДА;
(*============================================================================*
 * НАЗНАЧЕНИЕ: среда для выполнения Глагол-приложений.                        * 
 *   Распределяет память под создаваемые переменные и выполняет               *
 *     уборку памяти (УП) от неиспользуемых.                                  * 
 *   В исключительных состояниях (АвОстах) сохраняет в файл "Срез.пер"        * 
 *     значения переменных у запущенных задач (из стека приложения).          * 
 * ПРИМЕЧАНИЯ:                                                                * 
 *   Свободная память запрашивается у ОС кусками. Для создаваемой             * 
 *   переменной из 'куска памяти' выбирается свободный (или нарезается новый) * 
 *   участок памяти необходимого размера. Свойства участка хранятся в         * 
 *   описателе участка (ОУ), расположенном до значения переменной.            * 
 *   Для уборки памяти используются Данные о Видах во время выполнения (ДВ),  * 
 *   которые создаются Преобразователем Глагола (ПГ).                         * 
 *  'Куски памяти' организованны в кольцевой список.                          * 
 *                                                                            * 
 * Размещение ДВ набора в области ПОСТоянных:                                 * 
 * ДВ->  вид:4;   |                (Данных о Видах во время выполнения)       * 
 *       имя:...; } размерДВ ячеек                                            * 
 *       ...      |                                                           * 
 *       размерДВ     :4;                                                     * 
 *       адр(ДВ.имя)  :4;                                                     * 
 *       размер набора:4;                                                     * 
 * ОВ->  ОВ1:4;   |                (Описатель Вида)                           * 
 *       ОВ2:4;   |                                                           * 
 *       ...      } ВсегоРасширений шт.                                       * 
 *       0  :4;   |                                                           * 
 *       ...      |                                                           * 
 *       0  :4;   |                                                           * 
 *============================================================================*)
ИСПОЛЬЗУЕТ
  ОБХОД,
  ОС     ИЗ "..\Обмен\",
  Асм    ИЗ "..\Иное\",
  Буква  ИЗ "..\Иное\",
  Текст  ИЗ "..\Числа\",
  Вывод  ИЗ "..\Обмен\",
  Писать ИЗ "..\Обмен\";
ПОСТ
  (* размер запрашиваемого у ОС куска свободной памяти *)
  РазмерКуска=10000H; (* 10000H *)
  (* выделяется памяти перед принудительным запуском Уборки Памяти (УП) *)
  ЗапускУП=100*РазмерКуска;
  (* предельный уровень вложения доступов при записи среза переменных *)
  УровеньД=4;
  (* предельный уровень вложения  задач   при записи среза переменных *)
  УровеньЗ=30;   

  (* количественные ограничители Преобразователя Глагола (ПГ) *)
  рНазвания=32;       (* наибольший размер названия. Из отдела НП.            *)
  ВсегоРасширений=10; (* наибольший уровень расширения наборов. Из отдела ЗК. *)
  ВсегоОтделов=64;    (* количество отделов. Из отдела ВД.                    *)

  (* Программные ловушки/(аварийные остановы). Из отдела СК. *)
  пределыАвОст=1;
  номерАвОст=2;
  арифмАвОст=3;
  охранаАвОст=4;
  пустоАвОст=5;
  дляАвОст=6;
  выбратьАвОст=7;
  ответАвОст=8;
  проверитьАвОст=9;
  нольАвОст=10;
  бегунокАвОст=11;

  (* Род видов (Вид.родв). Из отдела ВД. Причём:
   * вЯчейка <= вЦел8 <= вЗнак <= вЦел16 <= вЦел32 <= вЦел64. *)
  вНеопр=0;
  вЯчейка=1;
  вКлюч=2;
  вЗнак=3;
  вЦел8=4;
  вЦел16=5;
  вЦел32=6;
  вЦел64=7;
  вВещ32=8;
  вВещ64=9;
  вМнож=10;
  вПЦепь=11;
  вПусто=12;
  вНет=13;
  вДоступ=14;
  вЗадача=15;
  вБегунок=16;
  вРяд=17;
  вОРяд=18;
  вНабор=19;
  вКон=20;
  (* вКон для ДВ. При изменении вКон нужно 3 преобразования с уборка:=ОТКЛ. *)
ВИД
(* описатель куска находится в начале каждого куска памяти,
 * полученного от ОС *)
  ОпКуска-=ДОСТУП К ВидОпКуска;
  ВидОпКуска=НАБОР
    первсв-:ЦЕЛ;    (* адрес первого свободного участка *)
    размер-:ЦЕЛ;    (* количество ячеек в куске памяти  *)
    первуч-:ЦЕЛ;    (* адрес первого участка памяти     *)
    следку-:ОпКуска (* для организации списка           *)
  КОН;
ПОСТ
  РазмерОК=16; (* размер описателя куска *)
ПОСТ
(* Позиции свойств описателя участка (ОУ) относительно его начала.
 * Описатель участка предшествует каждому участку памяти, выделенному
 * задачей СОЗДАТЬ. Т.к. преобразователь подразумевает, что 4 ячейки,
 * предшествующие данным, всегда содержат адрес описателя вида (ОВ),
 * то <ПозУчОВ> всегда должен указывать на последнее свойство ОУ. *)
  ПозУчРазмера-=0; (* размер участка (если <0, то участок свободен) *)
  ПозУчСледСв- =4; (* адрес следующего свободного участка           *)
  ПозУчОВ-     =4; (* адрес описателя вида (ОВ)                     *)
  РазмерОУ-    =8; (* размер описателя участка                      *)
ВИД
  Название-=ЦЕПЬ[рНазвания];

(* Описатель Отдела (ОО) создаётся преобразователем Глагола в области
 * постоянных *)
  ОпОтдела-=ДОСТУП К ВидОпОтдела;
  ВидОпОтдела=НАБОР
    название-        :Название;
    адрПерем-        :ЦЕЛ;  (* адрес переменных уровня отдела      *)
    адрПервЗадачи-   :ЦЕЛ;  (* адрес первой задачи                 *)
    адрЗаПослЗадачей-:ЦЕЛ;  (* адрес за последней задачей          *)
    адрДВПерем-      :ЦЕЛ;  (* адрес ДВ переменных уровня отдела   *)
    длДВПерем-       :ЦЕЛ;  (* длина ДВ переменных уровня отдела   *)
    описанияЗадач-   :РЯД 1 ИЗ НАБОР (* начало ряда описания задач *)
      нз-:ЦЕЛ;              (* адрес начала задачи    *)
      нч-:ЦЕЛ;              (* адрес начала ДВ задачи *)
    КОН
  КОН;
ПЕР
  опОтделов-:РЯД ВсегоОтделов ИЗ ЦЕЛ;   (* адреса описателей отделов     *)
  отделов-  :ЦЕЛ; (* всего адресов описателей отделов                     *)
  памПослеУП:ЦЕЛ; (* выделенно ячеек памяти после прошлой УП              *)
  уборка+   :КЛЮЧ;(* ВКЛ, если разрешена периодическая уборка памяти (УП) *)
  теккус-   :ЦЕЛ; (* адрес текущего куска в кольцевом списке кусков       *)
  тексвуч-  :ЦЕЛ; (* адрес свободного участка <теккус>                    *)

(* Запись среза переменных в исключительном состоянии *)
ПЕР
  поток:Писать.Поток; (* для записи среза переменных *)
  отступ:ЦЕЛ;         (* отступ на строке при записи среза *)
  уровеньд:ЦЕЛ;       (* текущий уровень вложения доступов при записи среза *)

(***************************************************************************
 * Задачи помощники для работы с видами и переменными приложения
 ***************************************************************************)

ЗАДАЧА ИмяИзОВ-(ов:ЦЕЛ; имя+:ЦЕПЬ);
ПЕР
  доступИмени:ДОСТУП К Название;
УКАЗ
  ЕСЛИ ов = 0 ТО
    СПИСАТЬ("ПУСТО",имя)
  ИНАЧЕ
    ОБХОД.ИзПамяти(ов-8,доступИмени);
    СПИСАТЬ(доступИмени^,имя)
  КОН
КОН ИмяИзОВ;

(******************************************************************************)
ЗАДАЧА ОВИзПер-(пер:ЦЕЛ; ов+:ЦЕЛ);
УКАЗ
  ЕСЛИ пер = 0 ТО
    ов:=0
  ИНАЧЕ
    ОБХОД.ИзПамяти(пер-РазмерОУ+ПозУчОВ,ов)
  КОН
КОН ОВИзПер;

(*
(******************************************************************************)
ЗАДАЧА ИмяВИзПер-(пер:ЦЕЛ; имя+:ЦЕПЬ);
ПЕР
  ов:ЦЕЛ;
УКАЗ
  ОВИзПер(пер,ов);
  ИмяИзОВ(ов,имя)
КОН ИмяВИзПер;
*)

(***************************************************************************
 * Задачи для чтения ДВ
 ***************************************************************************)
ЗАДАЧА ЦелИзДВ-(тч+,цел+:ЦЕЛ);
(* Цель:  прочитать целое число <цел> из ДВ
 * До:    <тч> - текущий адрес чтения ДВ *)
УКАЗ
  ОБХОД.ИзПамяти(тч,цел);
  УВЕЛИЧИТЬ(тч,4)
КОН ЦелИзДВ;

(******************************************************************************)
ЗАДАЧА ЦепьИзДВ-(тч+:ЦЕЛ; цепь+:ЦЕПЬ);
(* Цель:  прочитать в <цепь> цепочку знаков
 * До:    <тч> - текущий адрес чтения ДВ *)
ПЕР
  поз:ЦЕЛ;
  зн:ЗНАК;
УКАЗ
  поз:=0;
  ПОВТОРЯТЬ
    ОБХОД.ИзПамяти(тч,зн);
    УВЕЛИЧИТЬ(тч,2);
    ЕСЛИ поз < РАЗМЕР(цепь) ТО
      цепь[поз]:=зн
    КОН;
    УВЕЛИЧИТЬ(поз)
   ДО  зн = 0X
КОН ЦепьИзДВ;

(******************************************************************************)
ЗАДАЧА ВидИмяИзДВ-(тч+,вид+:ЦЕЛ; имя+:ЦЕПЬ);
(* Цель:  прочитать в <вид> метку ДВ, а в <имя> название ДВ
 * До:    <тч> - текущий адрес чтения ДВ *)
УКАЗ
  ЦелИзДВ(тч,вид); (* +вид *)
  ЦепьИзДВ(тч,имя) (* +имя *)
КОН ВидИмяИзДВ;

(******************************************************************************)
ЗАДАЧА НаборИзДВ-(нп,тч+:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ));
(* Цель:  обработать ДВ набора
 * До:    <нп> - адрес начала области переменных
 *        <тч> - текущий адрес чтения ДВ *)
ПЕР
  вид:ЦЕЛ;
УКАЗ
  ОБХОД.ИзПамяти(тч,вид);
  ПОКА вид # вКон ВЫП
    Обработка(нп,тч);
    ОБХОД.ИзПамяти(тч,вид)
  КОН;
  УВЕЛИЧИТЬ(тч,4)             (* +вид *)
КОН НаборИзДВ;

ЗАДАЧА^ ОтметитьВПер(нп,тч+:ЦЕЛ);

(******************************************************************************)
ЗАДАЧА ПропуститьДВ-(нп,тч+:ЦЕЛ);
(* Цель:  увеличить <тч> на столько, чтобы пропустить один ДВ
 * До:    <нп> - адрес начала области переменных
 *        <тч> - текущий адрес чтения ДВ *)
ПЕР
  вид:ЦЕЛ;
  имя:Название;
УКАЗ
  ВидИмяИзДВ(тч,вид,имя); (* +вид *)
  УВЕЛИЧИТЬ(тч,4);                     (* +оп  *)
  ВЫБРАТЬ вид ИЗ
    вДоступ:
      ВидИмяИзДВ(тч,вид,имя); (* +вид *)
      УВЕЛИЧИТЬ(тч,4);                 (* +оп *)
      ВЫБРАТЬ вид ИЗ
        вНабор:
          УМЕНЬШИТЬ(тч,4);             (* -оп *)
      | вРяд:
          УВЕЛИЧИТЬ(тч,8);             (* +рслаг +чслаг *)
          ПропуститьДВ(нп,тч)
      | вОРяд:
          УВЕЛИЧИТЬ(тч,4);             (* +рслаг *)
          ПропуститьДВ(нп,тч)
      | вБегунок:
          ПропуститьДВ(нп,тч)
      | вНеопр:
      КОН
  | вРяд:
      УВЕЛИЧИТЬ(тч,8);               (* +рслаг +чслаг *)
      ПропуститьДВ(нп,тч)
  | вБегунок:
      ПропуститьДВ(нп,тч)
  | вНабор:
      НаборИзДВ(нп,тч,ПропуститьДВ)
  ИНАЧЕ
  КОН
КОН ПропуститьДВ;

(******************************************************************************
 * Шаги по уборке памяти (УП):
 * а) все ранее распределённые участки памяти переводим в разряд
 *    неиспользуемых (выставляем их размеры отрицательными);
 * б) отмечаем участки памяти всех размещённых переменных доступных на
 *    данный момент как на уровне отдела так и через стек (в том числе и
 *    через переменные доступа), как используемые (выставляем их размеры
 *    положительными);
 * в) считаем, что оставшиеся участки с отрицательными размерами больше не
 *    используются приложением, и их можно использовать для новых переменных;
 * г) смежные свободные участки памяти объединяем;
 * д) целиком свободные куски памяти возвращаем ОС.
 ******************************************************************************)
ЗАДАЧА ОтметитьВРяду-(нпс,тч+,чслаг,рслаг:ЦЕЛ);
(* Цель:  отметить слагаемые ряда
 * До:    <нпс>   - адрес начала переменной слагаемого
 *        <тч>    - текущий адрес чтения ДВ
 *        <чслаг> - число слагаемых ряда
 *        <рслаг> - размер одного слагаемого *)
ПЕР
  тчс:ЦЕЛ; (* текущий адрес чтения ДВ слагаемого *)
  вид:ЦЕЛ; (* вид слагаемых *)
УКАЗ
  ОБХОД.ИзПамяти(тч,вид);
  ЕСЛИ вид В {вДоступ,вНабор,вРяд,вОРяд} ТО
    (* пробегаем по всем слагаемым *)
    ПОКА чслаг > 0 ВЫП
      тчс:=тч;
      ОтметитьВПер(нпс,тчс);
      УВЕЛИЧИТЬ(нпс,рслаг);
      УМЕНЬШИТЬ(чслаг)
    КОН;
    тч:=тчс
  ИНАЧЕ
    (* пропускаем ДВ слагаемого *)
    ПропуститьДВ(нпс,тч)
  КОН
КОН ОтметитьВРяду;

(******************************************************************************)
ЗАДАЧА ОтмечаемУчПер(пер:ЦЕЛ):КЛЮЧ;
(* Цель:  искать в куче и отметить участок памяти переменной с адресом <пер>
 * Ответ: ВКЛ, если участок ещё не был отмечен *)
ПЕР
  нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *)
  тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
  уч:    ЦЕЛ; (* адрес участка *)
  учпер: ЦЕЛ; (* адрес похожий на адрес участка переменной *)
  размуч:ЦЕЛ; (* размер участка *)
УКАЗ
  ЕСЛИ пер # 0 ТО (* не ПУСТО *)
    учпер:=пер-РазмерОУ;
    (* ищем кусок, содержащий учпер *)
    тк:=ОБХОД.Значение(ОпКуска,теккус);
    нк:=тк;
    ПОВТОРЯТЬ
      ЕСЛИ (учпер >= тк.первуч) И (учпер < тк.первуч+тк.размер) ТО (* нашли кусок *)
        (* ищем участок *)
        уч:=тк.первуч;
        ПОКА уч <= учпер ВЫП
          ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч);
          ЕСЛИ уч = учпер ТО
            (* нашли участок *)
            ЕСЛИ размуч < 0 ТО
              (* он ещё не отмечен занятым *)
              ОБХОД.ВПамять(уч+ПозУчРазмера,-размуч);
              ВОЗВРАТ ВКЛ
            ИНАЧЕ
              ВОЗВРАТ ОТКЛ
            КОН
          КОН;
          УВЕЛИЧИТЬ(уч,МОДУЛЬ(размуч))
        КОН
      КОН;
      тк:=тк.следку
     ДО  тк = нк (* обошли всё кольцо кусков *)
  КОН;
  ВОЗВРАТ ОТКЛ
КОН ОтмечаемУчПер;

ЗАДАЧА^ НаборИзД-(нп,ов:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ));

(******************************************************************************)
ЗАДАЧА ОтметитьВПер(нп,тч+:ЦЕЛ);
(* Цель: разбирая ДВ, найти размещённые переменные и отметить их участки памяти
 * До:   <нп> - адрес начала области переменных
 *       <тч> - текущий адрес чтения ДВ *)
ПЕР
  оп:ЦЕЛ;     (* адрес переменной относительно <нп> *)
  пп:ЦЕЛ;     (* полный адрес переменной <нп>+<оп>  *)
  ов:ЦЕЛ;     (* адрес ОВ                           *)
  зд:ЦЕЛ;     (* значение ДОСТУП                    *)
  вид:ЦЕЛ;    (* ДВ метка вида                      *)
  имя:Название;(* имя переменной (вида)             *)
  чслаг:ЦЕЛ;  (* число слагаемых ряда               *)
  рслаг:ЦЕЛ;  (* размер одного слагаемого           *)
  чразм:ЦЕЛ;  (* число размерностей у вОРяд         *)
  нразм:ЦЕЛ;  (* номер размерности вОРяд            *)
  длразм:ЦЕЛ; (* длина размерности вОРяд            *)
УКАЗ
  ВидИмяИзДВ(тч,вид,имя); (* +вид *)
  ЦелИзДВ(тч,оп);         (* +оп  *)
  ПРОВЕРИТЬ(вид # вНет);

  ВЫБРАТЬ вид ИЗ
    вДоступ:
      ОБХОД.ИзПамяти(нп+оп,зд);
      ВидИмяИзДВ(тч,вид,имя); (* +вид *)
      ЦелИзДВ(тч,оп);         (* +оп  *)
      ВЫБРАТЬ вид ИЗ
        вНабор:
          УМЕНЬШИТЬ(тч,4);    (* -оп     *)
          ЕСЛИ ОтмечаемУчПер(зд) ТО
            ОВИзПер(зд,ов);
            НаборИзД(зд,ов,ОтметитьВПер)
          КОН
      | вРяд:
          ЦелИзДВ(тч,рслаг);    (* +рслаг *)
          ЦелИзДВ(тч,чслаг);    (* +чслаг  *)
          ЕСЛИ ОтмечаемУчПер(зд) ТО
            ОтметитьВРяду(зд,тч,чслаг,рслаг)
          ИНАЧЕ
            ПропуститьДВ(зд,тч)
          КОН
      | вОРяд:
          ЦелИзДВ(тч,рслаг);    (* +рслаг *)
          (* по адресу ОРЯД 0-е слово содержит его размерность,
            * а следующие слова содержат РАЗМЕР его измерений   *)
          ЕСЛИ ОтмечаемУчПер(зд) ТО
            ОБХОД.ИзПамяти(зд,чразм);
            чслаг:=1;
            нразм:=1;
            ПОКА нразм <= чразм ВЫП
              ОБХОД.ИзПамяти(зд+нразм*4,длразм);
              чслаг:=чслаг*длразм;
              УВЕЛИЧИТЬ(нразм)
            КОН;
            ОтметитьВРяду(зд+нразм*4,тч,чслаг,рслаг)
          ИНАЧЕ
            ПропуститьДВ(зд,тч)
          КОН
      | вБегунок:
          ПропуститьДВ(нп,тч)
      | вНеопр:
      КОН
  | вРяд:
      ЦелИзДВ(тч,рслаг);      (* +рслаг *)
      ЦелИзДВ(тч,чслаг);      (* +чслаг  *)
      ОтметитьВРяду(нп+оп,тч,чслаг,рслаг)
  | вНабор:
      НаборИзДВ(нп,тч,ОтметитьВПер)
  | вБегунок:
      ПропуститьДВ(нп,тч)
  ИНАЧЕ
  КОН
КОН ОтметитьВПер;

(******************************************************************************)
ЗАДАЧА НаборИзД-(нп,ов:ЦЕЛ; Обработка:ЗАДАЧА (нп,тч+:ЦЕЛ));
(* Цель:  найти размещённые переменные набора и обработать их
 * До:    <нп> - адрес начала области переменных *)
ПЕР
  тч: ЦЕЛ; (* текущий адрес для чтения       *)
  вч: ЦЕЛ; (* всего ячеек для чтения         *)
  кч: ЦЕЛ; (* последний адрес для чтения     *)
  ур: ЦЕЛ; (* уровень расширения набора      *)
  ово:ЦЕЛ; (* адрес описателя вида основания *)
  имя:Название;
УКАЗ
  кч:=ов-12;
  ОБХОД.ИзПамяти(кч,вч);
  ИмяИзОВ(ов,имя);
  ЕСЛИ вч >= 0 ТО
    тч:=кч-вч;
    (* просмотр ДВ в нашем наборе *)
    ПОКА тч < кч ВЫП
      Обработка(нп,тч)
    КОН;
    (* просмотр ДВ в основаниях нашего набора *)
    ур:=ВсегоРасширений-1;
    КОЛЬЦО
      ЕСЛИ ур <= 0 ТО ВЫХОД КОН;
      ОБХОД.ИзПамяти(ов+ур*4,ово);
      ЕСЛИ ово # 0 ТО
        (* берём предпоследний ОВО, т.к. в последнем ОВО
          * хранится адрес своего ОВ *)
        ОБХОД.ИзПамяти(ов+(ур-1)*4,ово);
        НаборИзД(нп,ово,Обработка);
        ВЫХОД
      КОН;
      УМЕНЬШИТЬ(ур)
    КОН
  КОН
КОН НаборИзД;

(******************************************************************************)
ЗАДАЧА ОтметитьВЗадаче(нп,тч:ЦЕЛ);
(* Цель: разбирает ДВ задачи, находит размещённые переменные и отмечает их
 *       участки памяти как занятые
 * До:   <нп> - адрес начала переменных задачи (регистр EBP при работе задачи)
 *       <тч> - текущий адрес чтения ДВ *)
ПЕР
  вид:ЦЕЛ;    (* ДВ метка вида *)
  имя:Название;
УКАЗ
  ЦепьИзДВ(тч,имя);
  КОЛЬЦО
    ЦелИзДВ(тч,вид); (* +вид *)
    ЕСЛИ вид = вКон ТО
      ВЫХОД
    КОН;
    УМЕНЬШИТЬ(тч,4); (* -вид *)
    ОтметитьВПер(нп,тч)
  КОН
КОН ОтметитьВЗадаче;

(******************************************************************************)
ЗАДАЧА ОтметитьВОтделе(адрОО:ЦЕЛ);
(* Цель: разбирает ДВ отдела, находит размещённые переменные и отмечает их
 *       участки памяти как занятые *)
ПЕР
  тч:ЦЕЛ;      (* текущий адрес для чтения     *)
  кч:ЦЕЛ;      (* запоследний адрес для чтения *)
  оо:ОпОтдела; (* Описатель Отдела             *)
УКАЗ
  оо:=ОБХОД.Значение(ОпОтдела,адрОО);
  тч:=оо.адрДВПерем;
  кч:=тч+оо.длДВПерем;
  ПОКА тч < кч ВЫП
    ОтметитьВПер(оо.адрПерем,тч)
  КОН
КОН ОтметитьВОтделе;

(******************************************************************************)
ЗАДАЧА УдалитьСвКуски();
(* Цель:  найти полностью свободные куски памяти и возвратить их в ОС
 * Прим:  из кольцевого списка удобно удалять последующий кусок
 * После: <теккус>  - адрес начального куска в кольцевом списке кусков
 *        <тексвуч> - адрес первого свободного участка <теккус> *)
ПЕР
  тк:ОпКуска; (* текущий кусок в кольцевом списке кусков   *)
  ск:ОпКуска; (* следующий кусок в кольцевом списке кусков *)
  нк:ОпКуска; (* начальный неудаляемый кусок               *)
  размсв:ЦЕЛ; (* размер первого свободного участка в <ск>  *)
  удалёнск:КЛЮЧ; (* если был удалён <ск>, то ВКЛ           *)
  адрес:ЦЕЛ;  (* адрес памяти, возвращаемой в ОС           *)
УКАЗ
  тк:=ОБХОД.Значение(ОпКуска,теккус);
  ск:=тк.следку;
  нк:=ПУСТО;
  ПОВТОРЯТЬ
    удалёнск:=ОТКЛ;
    ЕСЛИ ск.первсв # 0 ТО
      ОБХОД.ИзПамяти(ск.первсв+ПозУчРазмера,размсв);
      ЕСЛИ ск.размер = -размсв ТО (* весь кусок свободен *)
        адрес:=ОБХОД.Значение(ЦЕЛ,ск);
        ЕСЛИ ск = тк ТО  (* был последним куском в списке *)
          ОС.ОтдатьПамять(адрес);
          теккус:=0;
          ВОЗВРАТ
        КОН;
        (* удаляем <ск> из кольцевого списка *)
        ск:=ск.следку;
        тк.следку:=ск;
        удалёнск:=ВКЛ;
        ОС.ОтдатьПамять(адрес)
      КОН
    КОН;
    ЕСЛИ НЕ удалёнск ТО
      ЕСЛИ нк = ПУСТО ТО
        нк:=ск
      КОН;
      (* продвигаем <тк> и <ск> *)
      тк:=ск;
      ск:=тк.следку
    КОН
   ДО  ск = нк; (* обошли всё кольцо кусков *)
  теккус:=ОБХОД.Значение(ЦЕЛ,нк);
  тексвуч:=нк.первсв
КОН УдалитьСвКуски;

(*
(******************************************************************************)
ЗАДАЧА ПроверитьКучу-();
(* Цель:  проверить строение всей кучи *)
ПЕР
  нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *)
  тк:ОпКуска; (* текущий кусок в кольцевом списке кусков   *)
  послуч:ЦЕЛ; (* адрес запоследнего участок в куске        *)
  уч:    ЦЕЛ; (* адрес текущего участка                    *)
  св:    ЦЕЛ; (* адрес свободного участка                  *)
  размуч:ЦЕЛ; (* размер <уч>                               *)
УКАЗ
  ЕСЛИ теккус = 0 ТО ВОЗВРАТ КОН;
  тк:=ОБХОД.Значение(ОпКуска,теккус);
  нк:=тк;
  ПОВТОРЯТЬ
    ПРОВЕРИТЬ((тк.размер > 0) И
      ((тк.размер+РазмерОК) ОСТАТОК РазмерКуска = 0) И
      (тк.первуч = (ОБХОД.Значение(ЦЕЛ,тк)+РазмерОК)));
    уч:=тк.первуч;
    послуч:=тк.первуч+тк.размер;
    св:=тк.первсв;
    ПОКА уч < послуч ВЫП
      ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч);
      ЕСЛИ размуч < 0 ТО (* свободный участок *)
        ПРОВЕРИТЬ(уч = св);
        ОБХОД.ИзПамяти(св+ПозУчСледСв,св);
        УВЕЛИЧИТЬ(уч,-размуч)
      ИНАЧЕ
        УВЕЛИЧИТЬ(уч,размуч)
      КОН
    КОН;
    ПРОВЕРИТЬ((уч = послуч) И (св = 0));
    тк:=тк.следку
   ДО  тк = нк  (* обошли всё кольцо кусков *)
КОН ПроверитьКучу;
*)

(******************************************************************************)
ЗАДАЧА GetEBP-():ЦЕЛ;
(* Цель: возвратить значение регистра EBP вызвавшей задаче *)
ПЕР
  п:ЦЕЛ;
УКАЗ
  п:=ОБХОД.ПолучитьАдрес(п)+4+4; (* после 'п': свой EBP, пред. EBP, пред. EIP *)
  ОБХОД.ИзПамяти(п,п);
  ВОЗВРАТ п
КОН GetEBP;

(******************************************************************************)
ЗАДАЧА НайтиДВЗадачи-(адр,но+,нч+:ЦЕЛ);
(* Цель:  найти задачу и её ДВ по внутреннему адресу задачи <адр>
 * После: <тч> - начальный адрес чтения ДВ
 *        <но> - номер отдела, в котором находится задача или 0 *)
ПЕР
  оо:ОпОтдела;(* Описатель Отдела *)
  оз:ЦЕЛ;     (* адрес Описания Задачи *)
  нз:ЦЕЛ;     (* адрес начала задачи *)
УКАЗ
  но:=0;
  ПОКА но < отделов ВЫП
    оо:=ОБХОД.Значение(ОпОтдела,опОтделов[но]);
    ЕСЛИ (адр >= оо.адрПервЗадачи) И (адр < оо.адрЗаПослЗадачей) ТО (* нашли отдел *)
      оз:=ОБХОД.ПолучитьАдрес(оо.описанияЗадач[0].нз);
      КОЛЬЦО
        ОБХОД.ИзПамяти(оз,нз);
        ЕСЛИ нз <= адр ТО (* нашли задачу *)
          ОБХОД.ИзПамяти(оз+4,нч);
          ВОЗВРАТ
        КОН;
        УВЕЛИЧИТЬ(оз,8) (* следующая запись *)
      КОН;
    КОН;
    УВЕЛИЧИТЬ(но)
  КОН;
КОН НайтиДВЗадачи;

(******************************************************************************)
ЗАДАЧА Уборка-();
(* Цель:  найти и объединить неиспользуемые участки памяти
 * После: <теккус>  - адрес начального куска в кольцевом списке кусков
 *        <тексвуч> - адрес первого свободного участка <теккус> *)
ПЕР
  но:    ЦЕЛ; (* номер отдела *)
  св:    ЦЕЛ; (* адрес группы свободных участков *)
  размуч:ЦЕЛ; (* размер участка *)
  послуч:ЦЕЛ; (* адрес первой ячейки после куска *)
  размсв:ЦЕЛ; (* размер группы свободных участков *)
  предсв:ЦЕЛ; (* адрес предыдущего свободного участка *)
  EBP:   ЦЕЛ; (* значение машинного регистра *)
  EIP:   ЦЕЛ; (* значение машинного регистра *)
  тч:    ЦЕЛ; (* текущий адрес чтения ДВ *)
  нк:ОпКуска; (* начальный кусок в кольцевом списке кусков *)
  тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
  уч:    ЦЕЛ; (* адрес текущего участка *)
  ц0:    ЦЕЛ; (* целый 0 *)
УКАЗ
  ЕСЛИ теккус = 0 ТО ВОЗВРАТ КОН;
  ц0:=0;

  (* размеры всех участков делаем отрицательными (как у свободных) *)
  нк:=ОБХОД.Значение(ОпКуска,теккус);
  тк:=нк;
  ПОВТОРЯТЬ
    уч:=тк.первуч;
    послуч:=уч+тк.размер;
    ПОКА уч < послуч ВЫП
      ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч);
      размуч:=МОДУЛЬ(размуч);
      ОБХОД.ВПамять(уч+ПозУчРазмера,-размуч);
      УВЕЛИЧИТЬ(уч,размуч)
    КОН;
    тк:=тк.следку
   ДО  тк = нк; (* обошли всё кольцо кусков *)

  (* отмечаем переменные всех отделов *)
  но:=0;
  ПОКА но < отделов ВЫП
    ОтметитьВОтделе(опОтделов[но]);
    УВЕЛИЧИТЬ(но)
  КОН;

  (* отмечаем переменные работающих задач (переменные стека) *)
  EBP:=GetEBP();
  КОЛЬЦО
    ОБХОД.ИзПамяти(EBP+4,EIP);    (* EIP вызвавшей задачи *)
    ОБХОД.ИзПамяти(EBP,EBP);      (* EBP вызвавшей задачи *)
    ЕСЛИ EBP = 0 ТО ВЫХОД КОН; (* вызвавшая задача - Пускач.^Запуск *)
    НайтиДВЗадачи(EIP,но,тч);
    ЕСЛИ но < отделов ТО
      ОтметитьВЗадаче(EBP,тч)
    КОН
  КОН;

  (* объединяем смежные свободные участки, и строим для них список *)
  тк:=нк;
  ПОВТОРЯТЬ
    св:=0;
    предсв:=0;
    уч:=тк.первуч;
    послуч:=уч+тк.размер;
    ПОКА уч < послуч ВЫП         (* по всем участкам куска *)
      ОБХОД.ИзПамяти(уч+ПозУчРазмера,размуч);
      ЕСЛИ размуч < 0 ТО         (* для свободного участка *)
        ЕСЛИ св = 0 ТО           (* если это начало области *)
          св:=уч;               (* сохраним её адрес *)
          размсв:=размуч        (* и начнем её замерять *)
        ИНАЧЕ                    (* продолжение области *)
          УВЕЛИЧИТЬ(размсв,размуч)      (* замеряем её дальше *)
        КОН
      АЕСЛИ св # 0 ТО            (* конец области *)
                                (* заранее обнуляем весь участок *)
        Асм.ОбнулитьПамять(св+РазмерОУ,-размсв-РазмерОУ);
                                (* выставляем окончательный размер области *)
        ОБХОД.ВПамять(св+ПозУчРазмера,размсв);
        ОБХОД.ВПамять(св+ПозУчСледСв,ц0);
        ЕСЛИ предсв = 0 ТО       (* первая область *)
          тк.первсв:=св         (* обновляем первсв в куске *)
        ИНАЧЕ                    (* уже была область *)
                                (* то выставляем у неё ссылку на нашу область *)
          ОБХОД.ВПамять(предсв+ПозУчСледСв,св)
        КОН;
        предсв:=св;             (* готовимся к следующей области *)
        св:=0
      КОН;
      УВЕЛИЧИТЬ(уч,МОДУЛЬ(размуч))
    КОН;
    (* такая же обработка в конце куска *)
    ЕСЛИ св # 0 ТО               (* конец области *)
                                (* заранее обнуляем весь участок *)
      Асм.ОбнулитьПамять(св+РазмерОУ,-размсв-РазмерОУ);
                                (* выставляем окончательный размер области *)
      ОБХОД.ВПамять(св+ПозУчРазмера,размсв);
      ОБХОД.ВПамять(св+ПозУчСледСв,ц0);
      ЕСЛИ предсв = 0 ТО         (* первая область *)
        тк.первсв:=св           (* записываем ссылку в куске *)
      ИНАЧЕ                      (* уже была предобласть *)
                                (* то выставляем у неё ссылку на область *)
        ОБХОД.ВПамять(предсв+ПозУчСледСв,св)
      КОН
    КОН;
    тк:=тк.следку
   ДО  тк = нк; (* обошли всё кольцо кусков *)

  УдалитьСвКуски();
  памПослеУП:=0
КОН Уборка;

(******************************************************************************)
ЗАДАЧА НаходимСвобУч(размер:ЦЕЛ):КЛЮЧ;
(* Цель:  искать по всем кускам участок памяти не меньше <размер> ячеек
 * Прим:  если находит такой участок, то возвращает ВКЛ и
 * После: <теккус>  - адрес куска из кольцевого списка
 *        <тексвуч> - адрес свободного участка <теккус> *)
ПЕР
  тк:ОпКуска; (* текущий кусок в кольцевом списке кусков              *)
  нк:ОпКуска; (* кусок с которого начинается поиск                    *)
  нсвуч: ЦЕЛ; (* адрес свободного участка с которого начинается поиск *)
  размсв:ЦЕЛ; (* размер свободного <тексвуч>                          *)
УКАЗ
  ЕСЛИ теккус = 0 ТО ВОЗВРАТ ОТКЛ КОН;
  тк:=ОБХОД.Значение(ОпКуска,теккус);
  нк:=тк;
  нсвуч:=тексвуч;
  ПОВТОРЯТЬ
    ПОКА тексвуч = 0 ВЫП (* кончился кусок *)
      тк:=тк.следку;
      теккус:=ОБХОД.Значение(ЦЕЛ,тк);
      тексвуч:=тк.первсв;
      ЕСЛИ (тк = нк) И (тексвуч = нсвуч) ТО (* обошли все участки *)
        ВОЗВРАТ ОТКЛ
      КОН
    КОН;
    ОБХОД.ИзПамяти(тексвуч+ПозУчРазмера,размсв);
    ЕСЛИ -размсв >= размер ТО
      ВОЗВРАТ ВКЛ
    КОН;
    ОБХОД.ИзПамяти(тексвуч+ПозУчСледСв,тексвуч)
   ДО  (тк = нк) И (тексвуч = нсвуч); (* обошли все участки *)
  ВОЗВРАТ ОТКЛ
КОН НаходимСвобУч;

(******************************************************************************)
ЗАДАЧА СоздатьКусок(размер:ЦЕЛ);
(* Цель:  запрос у ОС нового куска памяти с полезным размером <размер>
 * После: <теккус>  - адрес нового текущего куска в кольцевом списке кусков
 *        <тексвуч> - адрес первого (и единственного) участка <теккус> *)
ПЕР
  нк:ОпКуска; (* новый кусок в кольцевом списке кусков   *)
  тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
  ц0:    ЦЕЛ; (* целый 0                                 *)
УКАЗ
  ц0:=0;
  тк:=ОБХОД.Значение(ОпКуска,теккус);
  УВЕЛИЧИТЬ(размер,РазмерОК);
  УВЕЛИЧИТЬ(размер,(-размер) ОСТАТОК РазмерКуска); (* выравнивание на РазмерКуска *)
  теккус:=ОС.ВзятьПамять(размер);
  ПРОВЕРИТЬ(теккус # 0);
  нк:=ОБХОД.Значение(ОпКуска,теккус);
  тексвуч:=теккус+РазмерОК; (* оставляем место для <нк> *)
  УМЕНЬШИТЬ(размер,РазмерОК);
  нк.размер:=размер;
  нк.первуч:=тексвуч;
  нк.первсв:=тексвуч;
  ОБХОД.ВПамять(тексвуч+ПозУчСледСв,ц0);
  ОБХОД.ВПамять(тексвуч+ПозУчРазмера,-размер);
  (* вставляем новый кусок в кольцевой список после текущего куска *)
  ЕСЛИ тк # ПУСТО ТО
    нк.следку:=тк.следку;
    тк.следку:=нк
  ИНАЧЕ
    нк.следку:=нк
  КОН
КОН СоздатьКусок;

(******************************************************************************)
ЗАДАЧА СоздатьУч(размер:ЦЕЛ):ЦЕЛ;
(* Цель:  создать участок с размером <размер> (в конце <тексвуч>
 *        или весь <тексвуч>) и возвратить его адрес
 * До:    <теккус>  - адрес текущего куска в кольцевом списке кусков
 *        <тексвуч> - адрес достаточно большого свободного участка в <теккус>
 * После: <тексвуч> - бывший или следующий адрес свободного участка *)
ПЕР
  предсв:ЦЕЛ; (* адрес предыдущего свободного участка    *)
  размсв:ЦЕЛ; (* размер свободного участка               *)
  тк:ОпКуска; (* текущий кусок в кольцевом списке кусков *)
  уч:    ЦЕЛ; (* адрес свободного участка                *)
  создуч:ЦЕЛ; (* адрес созданного участка                *)
УКАЗ
  ОБХОД.ИзПамяти(тексвуч+ПозУчРазмера,размсв);
  размсв:=-размсв; (* размер будет положительным *)
  ЕСЛИ размсв > размер+РазмерОУ+4 ТО (* забираем хвост у <тексвуч> *)
    УМЕНЬШИТЬ(размсв,размер);
    ОБХОД.ВПамять(тексвуч+ПозУчРазмера,-размсв);
    создуч:=тексвуч+размсв;
    ОБХОД.ВПамять(создуч+ПозУчРазмера,размер);
    (* ссылки в списке свободных участков остались те же *)
  ИНАЧЕ (* забираем целиком <тексвуч> *)
    создуч:=тексвуч;
    ОБХОД.ВПамять(создуч+ПозУчРазмера,размсв);
    (* новый <тексвуч> *)
    ОБХОД.ИзПамяти(создуч+ПозУчСледСв,тексвуч);
    (* удаляем <создуч> из списка свободных участков *)
    тк:=ОБХОД.Значение(ОпКуска,теккус);
    ЕСЛИ создуч = тк.первсв ТО (* это <первсв> в куске *)
      тк.первсв:=тексвуч
    ИНАЧЕ
      предсв:=тк.первсв; (* ищем предыдущий свободный участок *)
      уч:=предсв;
      ПОКА уч # создуч ВЫП
        предсв:=уч;
        ОБХОД.ИзПамяти(уч+ПозУчСледСв,уч)
      КОН;
      ОБХОД.ВПамять(предсв+ПозУчСледСв,тексвуч)
    КОН
  КОН;
  ВОЗВРАТ создуч
КОН СоздатьУч;

(***************************************************************************
 * Задачи, вызываемые из приложения неявным образом
 ***************************************************************************)

ЗАДАЧА Создать-(ов,размер,адрес+:ЦЕЛ);
(* Цель:  поддержка встроенных в Глагол задач:
 *        СОЗДАТЬ(<пер>+:вид)                      - для наборов и рядов
 *        СОЗДАТЬ(<пер>+:вид; <ДЛ1>,...,<ДЛn>:ЦЕЛ) - для открытых рядов
 * До:    <ов>     - описатель вида переменной <пер>
 *                   для рядов и открытых рядов <ов> = 0
 *        <размер> - размер данных у <пер>
 *                   для открытых рядов <размер> = 4+n*4+<ДЛ1>*...*<ДЛn>
 * После: <адрес>  - адрес выделенной памяти заполненной 0-ми,
 *                   четыре ячейки перед <адрес> всегда содержат <ов> *)
ПЕР
  уч:ЦЕЛ; (* адрес свободного участка *)
УКАЗ
  УВЕЛИЧИТЬ(размер,РазмерОУ);
  УВЕЛИЧИТЬ(размер,(-размер) ОСТАТОК 4); (* выравнивание *)
  ЕСЛИ НЕ НаходимСвобУч(размер) ТО
    ЕСЛИ уборка И (памПослеУП >= ЗапускУП) ТО
      Уборка();
      ЕСЛИ НЕ НаходимСвобУч(размер) ТО
        СоздатьКусок(размер)
      КОН
    ИНАЧЕ
      СоздатьКусок(размер)
    КОН
  КОН;
  ЕСЛИ размер < РазмерКуска ТО
    УВЕЛИЧИТЬ(памПослеУП,размер)
  КОН;
  уч:=СоздатьУч(размер);
  ОБХОД.ВПамять(уч+ПозУчОВ,ов);
  адрес:=уч+РазмерОУ
КОН Создать;

(******************************************************************************)
ЗАДАЧА Присоединить-(адрОО:ЦЕЛ);
(* Цель:  присоединить к среде отдел, где <адрОО> адрес описателя отдела,
 *        расположенного в постоянной области кода
 * Прим:  вызывается однократно для каждого отдела при запуске приложения *)
УКАЗ
  ПРОВЕРИТЬ(отделов < ВсегоОтделов);
  опОтделов[отделов]:=адрОО;
  УВЕЛИЧИТЬ(отделов)
КОН Присоединить;

(***************************************************************************
 * Запись среза значений переменных работающих задач в исключительном состоянии
 ***************************************************************************)

ЗАДАЧА^ Пер(нп,тч+:ЦЕЛ);

(******************************************************************************)
ЗАДАЧА Цепь(цепь-:ЦЕПЬ);
УКАЗ
  Писать.Цепь(поток,цепь)
КОН Цепь;

(******************************************************************************)
ЗАДАЧА Цел(описание-:ЦЕПЬ; ц:ШИРЦЕЛ);
УКАЗ
  Писать.ЧЦел(поток,описание,ц,0,0,0);
КОН Цел;

(******************************************************************************)
ЗАДАЧА Вещ(описание-:ЦЕПЬ; в:ШИРВЕЩ);
УКАЗ
  Писать.ЧВещ(поток,описание,в,0,0,0);
КОН Вещ;

(******************************************************************************)
ЗАДАЧА Ряд(нпс,тч+,чслаг,рслаг:ЦЕЛ);
(* Цель:  выписать значения всех слагаемых ряда
 * До:    <нпс>   - адрес начала переменной слагаемого
 *        <тч>    - текущий адрес чтения ДВ
 *        <чслаг> - число слагаемых в ряду
 *        <рслаг> - размер одного слагаемого *)
ПЕР
  зз:ЗНАК;     (* ЗНАК значение                      *)
  тчс:ЦЕЛ;     (* текущий адрес чтения ДВ слагаемого *)
  вид:ЦЕЛ;     (* ДВ метка вида                      *)
  имя:Название;(* название переменной (вида)         *)
УКАЗ
  тчс:=тч;
  ВидИмяИзДВ(тчс,вид,имя); 
  ЕСЛИ вид = вЗнак ТО (* цепочка знаков *)
    Цепь('"');
    КОЛЬЦО
      ЕСЛИ чслаг <= 0 ТО ВЫХОД КОН;
      ОБХОД.ИзПамяти(нпс,зз);
      ЕСЛИ зз = 0X ТО
        ВЫХОД
      АЕСЛИ ((зз >= ' ') И (зз <= '#007F')) ИЛИ Буква.Известная(зз) ТО
        Цел("%c",ВЦЕЛ(зз))
      ИНАЧЕ
        Цел("##%.4x",ВЦЕЛ(зз))
      КОН;
      УВЕЛИЧИТЬ(нпс,рслаг);
      УМЕНЬШИТЬ(чслаг)
    КОН;
    Цепь('"');
    тч:=тчс+4 (* +оп *)
  ИНАЧЕ
    УВЕЛИЧИТЬ(отступ,2);
    ПОКА чслаг > 0 ВЫП
      тчс:=тч;
      Пер(нпс,тчс);
      УВЕЛИЧИТЬ(нпс,рслаг);
      УМЕНЬШИТЬ(чслаг)
    КОН;
    УМЕНЬШИТЬ(отступ,2);
    тч:=тчс
  КОН;
КОН Ряд;

(******************************************************************************)
ЗАДАЧА ИмяЗадачи(аз,тч+:ЦЕЛ);
(* Цель:  выписать полное название задачи
 * До:    <аз> - произвольный адрес внутри кода задачи
 *        <тч> - текущий адрес чтения ДВ *)
ПЕР
  оо:ОпОтдела; (* описатель отдела *)
  но:ЦЕЛ;      (* № отдела         *)
  имя:Название;(* имя задачи       *)
УКАЗ
  НайтиДВЗадачи(аз,но,тч);
  ЕСЛИ но < отделов ТО
    оо:=ОБХОД.Значение(ОпОтдела,опОтделов[но]);
    Цепь(оо.название);
    Цепь(".");
    ЦепьИзДВ(тч,имя);
    Цепь(имя)
  ИНАЧЕ
    Цепь("ПУСТО");
    тч:=0
  КОН
КОН ИмяЗадачи;

(******************************************************************************)
ЗАДАЧА Пер(нп,тч+:ЦЕЛ);
(* Цель:  выписать значение переменной
 * До:    <нп> - адрес начала области переменных
 *        <тч> - текущий адрес чтения ДВ *)
ПЕР
  оп:ЦЕЛ;     (* адрес переменной относительно <нп> *)
  пп:ЦЕЛ;     (* полный адрес переменной <нп>+<оп>  *)
  ов:ЦЕЛ;     (* адрес ОВ                           *)
  зз:ЗНАК;    (* ЗНАК значение                      *)
  ц8:ОБХОД.Цел8;    (* Цел8 значение                      *)
  ц16:ОБХОД.Цел16;  (* Цел16 значение                     *)
  ц32:ОБХОД.Цел32;  (* Цел32 значение                     *)
  ц64:ОБХОД.Цел64;  (* Цел64 значение                     *)
  в32:ОБХОД.Вещ32;  (* Вещ32 значение                     *)
  в64:ОБХОД.Вещ64;  (* Вещ64 значение                     *)
  ц :ЦЕЛ;     (* ЦЕЛ значение                       *)
  дз:ЦЕЛ;     (* ДОСТУП значение                    *)
  тб:ЦЕЛ;     (* текущее значение бегунка           *)
  нб:ЦЕЛ;     (* начало ряда бегунка                *)
  кб:ЦЕЛ;     (* конец ряда бегунка                 *)
  вид:ЦЕЛ;    (* ДВ метка вида                      *)
  имя:Название;(* название переменной (вида)        *)
  чслаг:ЦЕЛ;  (* число слагаемых ряда               *)
  рслаг:ЦЕЛ;  (* размер одного слагаемого           *)
  чразм:ЦЕЛ;  (* число размерностей у вОРяд         *)
  нразм:ЦЕЛ;  (* номер размерности вОРяд            *)
  длразм:ЦЕЛ; (* длина размерности вОРяд            *)
УКАЗ
  ВидИмяИзДВ(тч,вид,имя); (* +вид  *)
  ЦелИзДВ(тч,оп);         (* +оп  *)
  пп:=нп+оп;
  Цел("^%*",отступ);
  Цепь(имя);
  Цепь("=");
  ВЫБРАТЬ вид ИЗ
    вЯчейка:
      ОБХОД.ИзПамяти(пп,ц8);
      ц:=ц8;
      ЕСЛИ ц < 0 ТО
        УВЕЛИЧИТЬ,100H)
      КОН;
      Цел("%.2xH",ц)
  | вКлюч:
      ОБХОД.ИзПамяти(пп,ц8);
      Цел("%d",ц8)
  | вЗнак:
      ОБХОД.ИзПамяти(пп,зз);
      ЕСЛИ ((зз >= ' ') И (зз <= '#007F')) ИЛИ Буква.Известная(зз) ТО
        Цел("'%c'",ВЦЕЛ(зз))
      ИНАЧЕ
        Цел("%.4xX",ВЦЕЛ(зз))
      КОН
  | вЦел8:
      ОБХОД.ИзПамяти(пп,ц8);
      Цел("%d",ц8)
  | вЦел16:
      ОБХОД.ИзПамяти(пп,ц16);
      Цел("%d",ц16)
  | вЦел32:
      ОБХОД.ИзПамяти(пп,ц32);
      Цел("%d",ц32)
  | вЦел64:
      ОБХОД.ИзПамяти(пп,ц64);
      Цел("%d",ц64)
  | вВещ32:
      ОБХОД.ИзПамяти(пп,в32);
      Вещ("%g",в32)
  | вВещ64:
      ОБХОД.ИзПамяти(пп,в64);
      Вещ("%g",в64)
  | вМнож:
      ОБХОД.ИзПамяти(пп,ц32);
      Цел("%.8xH",ц32)
  | вЗадача:
      ОБХОД.ИзПамяти(пп,дз);
      ИмяЗадачи(дз,дз)
  | вБегунок:
      ОБХОД.ИзПамяти(пп+0,тб);
      ОБХОД.ИзПамяти(пп+4,нб);
      ОБХОД.ИзПамяти(пп+8,кб);
      ЕСЛИ уровеньд >= УровеньД ТО
        ПропуститьДВ(нп,тч)
      АЕСЛИ тб = 0 ТО
        Цепь("ПУСТО");
        ПропуститьДВ(нп,тч)
      АЕСЛИ тб < нб ТО  (* работает, если ВКЛ проверки *)
        Цепь("до ряда");
        ПропуститьДВ(нп,тч)
      АЕСЛИ тб >= кб ТО (* работает, если ВКЛ проверки *)
        Цепь("после ряда");
        ПропуститьДВ(нп,тч)
      ИНАЧЕ
        УВЕЛИЧИТЬ(уровеньд);
        УВЕЛИЧИТЬ(отступ,2);
        Пер(тб,тч);
        УМЕНЬШИТЬ(отступ,2);
        УМЕНЬШИТЬ(уровеньд)
      КОН;
  | вДоступ:
      ОБХОД.ИзПамяти(пп,дз);
      ВидИмяИзДВ(тч,вид,имя); (* +вид  *)
      ЦелИзДВ(тч,оп);         (* +оп   *)
      ВЫБРАТЬ вид ИЗ
        вНабор:
          УМЕНЬШИТЬ(тч,4);                   (* -оп   *)
          ЕСЛИ дз = 0 ТО
            Цепь("ПУСТО")
          ИНАЧЕ
            ЕСЛИ уровеньд < УровеньД ТО
              УВЕЛИЧИТЬ(уровеньд);
              ОВИзПер(дз,ов);
              УВЕЛИЧИТЬ(отступ,2);
              НаборИзД(дз,ов,Пер);
              УМЕНЬШИТЬ(отступ,2);
              УМЕНЬШИТЬ(уровеньд)
            КОН
          КОН
      | вНеопр:
          Цепь("ОБХОД.Доступ")
      | вРяд:
          ЦелИзДВ(тч,рслаг);    (* +рслаг   *)
          ЦелИзДВ(тч,чслаг);    (* +чслаг  *)
          ЕСЛИ (дз = 0) ИЛИ (уровеньд >= УровеньД) ТО
            ЕСЛИ дз = 0 ТО
              Цепь("ПУСТО")
            КОН;
            ПропуститьДВ(нп,тч)
          ИНАЧЕ
            УВЕЛИЧИТЬ(уровеньд);
            Ряд(дз,тч,чслаг,рслаг);
            УМЕНЬШИТЬ(уровеньд)
          КОН
      | вОРяд:
          ЦелИзДВ(тч,рслаг);   (* +рслаг *)
          (* по адресу ОРЯД 0-е слово содержит его размерность,
           * а следующие слова содержат РАЗМЕРы его измерений *)
          ЕСЛИ (дз = 0) ИЛИ (уровеньд >= УровеньД) ТО
            ЕСЛИ дз = 0 ТО
              Цепь("ПУСТО")
            КОН;
            ПропуститьДВ(нп,тч)
          ИНАЧЕ
            УВЕЛИЧИТЬ(уровеньд);
            ОБХОД.ИзПамяти(дз,чразм);
            чслаг:=1;
            нразм:=1;
            ПОКА нразм <= чразм ВЫП
              ОБХОД.ИзПамяти(дз+нразм*4,длразм);
              чслаг:=чслаг*длразм;
              УВЕЛИЧИТЬ(нразм)
            КОН;
            Ряд(дз+нразм*4,тч,чслаг,рслаг);
            УМЕНЬШИТЬ(уровеньд)
          КОН
      | вБегунок:
          ПропуститьДВ(нп,тч)
      КОН
  | вРяд:
      ЦелИзДВ(тч,рслаг);      (* +рслаг  *)
      ЦелИзДВ(тч,чслаг);      (* +чслаг  *)
      Ряд(пп,тч,чслаг,рслаг)
  | вНабор:
      УВЕЛИЧИТЬ(отступ,2);
      НаборИзДВ(нп,тч,Пер);
      УМЕНЬШИТЬ(отступ,2)
  ИНАЧЕ
    Цепь("НЕИЗВЕСТНЫЙ вид")
  КОН
КОН Пер;

(******************************************************************************)
ЗАДАЧА ПерСтека(EBP:ЦЕЛ);
ПЕР
  EIP:ЦЕЛ;     (* значение машинного регистра *)
  тч: ЦЕЛ;     (* текущий адрес чтения ДВ *)
  вид:ЦЕЛ;     (* ДВ метка вида *)
  уровеньз:ЦЕЛ;(* уровень вложения задач *)
УКАЗ
  уровеньз:=0;
  КОЛЬЦО
    ЕСЛИ уровеньз >= УровеньЗ ТО ВЫХОД КОН;
    ОБХОД.ИзПамяти(EBP+4,EIP);    (* EIP вызвавшей задачи *)
    ОБХОД.ИзПамяти(EBP,EBP);      (* EBP вызвавшей задачи *)
    ЕСЛИ EBP = 0 ТО ВЫХОД КОН;    (* вызвавшая задача - Пускач._Nachalo *)
    Цепь("^^Переменные задачи ");
    ИмяЗадачи(EIP,тч);
    ЕСЛИ тч # 0 ТО
      отступ:=2;
      КОЛЬЦО
        ЦелИзДВ(тч,вид); (* +вид *)
        ЕСЛИ вид = вКон ТО ВЫХОД КОН;
        УМЕНЬШИТЬ(тч,4); (* -вид *)
        Пер(EBP,тч)
      КОН
    КОН;
    УВЕЛИЧИТЬ(уровеньз)
  КОН
КОН ПерСтека;

(******************************************************************************)
ЗАДАЧА Ловушка-(адрОО,кодстрока:ЦЕЛ);
(* Цель:  ловушка исключений *)
ПЕР
  EBP:ЦЕЛ;
  код,строка:ЦЕЛ;
  оо:ОпОтдела;
  текст:ЦЕПЬ[100];
УКАЗ
  EBP:=GetEBP();
  оо:=ОБХОД.Значение(ОпОтдела,адрОО);
  код:=кодстрока ОСТАТОК 10000H;
  строка:=кодстрока ДЕЛИТЬ 10000H;
  Вывод.Цепь('^Сработала ловушка в отделе "');
  Вывод.Цепь(оо.название);
  Текст.ИзЧЦел('" на строке %d.^Причина: ',строка,0,0,0,текст);
  Вывод.Цепь(текст);
  ВЫБРАТЬ код ИЗ
  | пределыАвОст:  текст:='выход значения за допустимые пределы'
  | номерАвОст:    текст:='неверный номер переменной ряда'
  | арифмАвОст:    текст:='арифметическое переполнение'
  | охранаАвОст:   текст:='неверный размещённый вид'
  | пустоАвОст:    текст:='значение доступа "ПУСТО"'
  | дляАвОст:      текст:='у "ДЛЯ" нет "ИНАЧЕ"'
  | выбратьАвОст:  текст:='у "ВЫБРАТЬ" нет "ИНАЧЕ"'
  | ответАвОст:    текст:='не определён ответ'
  | проверитьАвОст:текст:='"ПРОВЕРИТЬ" выдаёт ошибку'
  | нольАвОст:     текст:='деление на ноль'
  | бегунокАвОст:  текст:='бегунок вне ряда'
  ИНАЧЕ
    Текст.ИзЧЦел('код %d',код,0,0,0,текст)
  КОН;
  Вывод.Цепь(текст);
  Вывод.Цепь('.^Подробности см. в файле "Срез.пер".^');
  поток:=Писать.Открыть("Срез.пер");
  поток.видЗнаков:=Писать.знУни;
  Цепь(текст);
  ПерСтека(EBP);
  Писать.Закрыть(поток);
  СТОП(код)
КОН Ловушка;

(******************************************************************************)
УКАЗ
  уборка:=ВКЛ
КОН СРЕДА.

 
 


Вопросы, замечания и предложения высылайте на atimopheyev@yahoo.com

 
Главная     ◄Глагол     ◄Азбука     ◄Задачи на Глаголе     Примеры приложений ►   Среда разработки ►   Отладка программ ►   Отличия от Оберона ►   Отличия от Паскаля ►   Ассемблер ARM ►   Глагол для ARM ►   ? и Ответы